テクニカル Q&A

DV36 - MemAllocatePhysicallyContiguous (1999 年 8 月 23 日)


Q: 私のドライバには物理的に連続したメモリを割り当てる必要があります。MemAllocatePhysicallyContiguous を呼び出していますが、システムに使用可能なメモリが十分あっても、nil を返します。どうしたらよいのでしょうか。

A: MemAllocatePhysicallyContiguous は物理的に連続したメモリを探すのに非常に単純なアルゴリズムを使っています。アルゴリズムの要点は以下の通りです。

on MemAllocatePhysicallyContiguous size
    result = NewPtrSys(size)
    if result != nil then
        if LockMemoryContiguous(result, size) != noErr then
            previousResult = result;
            result = NewPtrSys(size)
            if result != nil then
                if LockMemoryContiguous(result, size) != noErr then
                    DisposePtr(result)
                    result = nil;
                end-if
            end-if
            DisposePtr(previousResult)
        end-if
    end-if
    return result
end MemAllocatePhysicallyContiguous

注意 :
上記の疑似コードは MemAllocatePhysicallyContiguous アルゴリズムを簡単に表したものです。実際のコードは、MemAllocatePhysicallyContiguous が返すバッファは常にページ境界に揃うことなどのため、もっと複雑です。

このアルゴリズムは連続した物理メモリを探す方法として、あまり洗練されたものではありません。具体的には、連続した物理メモリブロックを 2 回探しています。2 回とも失敗すれば、MemAllocatePhysicallyContiguous はあきらめてエラーを返します。実際には十分なメモリがあって、十分な連続した物理メモリがあっても、MemAllocatePhysicallyContiguous は見つけられないことがあります。

MemAllocatePhysicallyContiguous が使用する LockMemoryContiguous 呼び出しの成功を左右する要因はたくさんあります。

  • VM がロードされる前は、論理アドレスと物理アドレスとの関係は比較的単純です。普通、論理アドレスと物理アドレスとの間には 1 対 1 の対応があります。しかし、常にそうなっているとは限りません。
    • RAM 領域に ROM 領域が混在する形式(ROM-in-RAM)のコンピュータでは、システムの Open Firmware から Mac OS への移行手順や、Mac OS ROM ファイルのメモリへのロード方法に応じて、論理メモリと物理メモリ間のマッピングには多数の不連続が生じています。この問題の背景の詳細については、DTS Q&A DV 33「PrepareMemoryForIO in the NewWorld」を参照してください。
    • こうした不連続は新しい事柄ではありません。歴史的に見て、Mac IIci などの機種はメモリ管理ユニットで、物理アドレス空間の不連続な RAM バンクを「縫い」合わせていました。

    お問い合せのドライバは、ブート時に、ハードウェアプラットフォーム、RAM の構成、ドライバロードのタイミング、ロード済みドライバのメモリ消費量などの要因で、このような不連続に遭遇している可能性があります。

  • VM のロード後、物理アドレスと論理アドレスの対応関係はすぐに乱雑になります。
  • ROM には LockMemoryContiguous の初期バージョンが入っていて、これは単にメモリが物理的に連続しているかどうかをチェックし、連続していなければ cannotMakeContiguousErr を返します。VM のロード前に (または、VM がオフになっているシステムで) 連続した物理メモリを取得しようとすると、このバージョンの LockMemoryContiguous が使われます。
  • 仮想メモリマネージャは、いくらか洗練されたアルゴリズムを使用する LockMemoryContiguous を再実装しています。VM が使用可能で、VM のロード後に連続した物理メモリの取得を試みると、この新しいアルゴリズムが機能し、これまでより熱心に連続した物理メモリ領域を探します。しかし、それでも巨大なブロックの連続した物理メモリの要求は失敗する可能性があります。

要約すると、システムが連続した物理メモリを提供する能力は非常に限られていて、環境的な要因から著しい影響を受けます。

悪い情報はここまでです。幸いにも、この制限は回避することができるので、これからその方法を紹介します。

  • 少量のメモリを割り当てる ― 割り当てるメモリの量が少ないほど、メモリが連続している可能性は大きくなります (極端な話をすると、1 ページ分の連続した物理メモリの割り当ては常に成功します)。巨大な連続した物理メモリブロックを 1 個だけ割り当てようとするのは、最悪の方法です。ドライバを再構築して、より小さいブロックのメモリを多数使用するようにした方がよいでしょう。
  • メモリを早期に割り当てる ― ロードされるタイミングが早いほど、連続した物理メモリを割り当てられる可能性が高くなります。ドライバの中には、オープンされるまでメモリの割り当てを行わず、結果的にその時にはもう連続した物理メモリを取得できないものがあります。これを避けるためには、kDriverIsLoadedUponDiscovery フラグを指定して、ドライバが起動処理を行っている早い段階でメモリの割り当てを可能にすることです。こうすればドライバがオープンされたときには、割り当て済みのメモリを使用することができるというわけです。
  • 後からメモリを割り当てる ― 起動時にメモリの割り当てができないときは、ドライバがオープンされたときや、起動処理の後半でロードされる何らかの他のサービスがドライバにアクセスしてきたときに、割り当てを試みることができます。VM の改善された LockMemoryContiguous アルゴリズムが使用できるため、後から割り当てを行うと成功する確率が高まります。
  • 分散/収集方式 ― DMA ハードウェアのほとんどが分散/収集機構 (scatter/gather) をサポートしています (分散/収集ハードウェアは、連続した物理メモリの割り当て機構を提供しない OS では必須のものです)。デベロッパの多くは分散/収集を敬遠しがちです。効率が落ちること (ディスクリプタを参照するため PCI バスサイクルを消費します)、プログラムが難しいことがその理由です。しかし、分散/収集は、MemAllocatePhysicallyContiguous が nil を返した場合の最終的な解決策です。

以上のテクニックを組み合わせて使えば、最良の結果が得られるでしょう。連続した物理メモリを使うことでカードの性能が大幅に向上するならば、上で説明したテクニックを使って連続した物理メモリを割り当てるべきです。連続した物理メモリ割り当ての試みがすべて失敗した場合、最後の手段として、ハードウェアの分散/収集モードを使用可能にしておくべきでしょう。


-- Quinn "The Eskimo!"
Worldwide Developer Technical Support


テクニカル Q&A | 目次

To contact us, please use the Contact Us page.